/*
* Copyright (c) 2008-2011, Thomas Handorf, Nils Christian
* 
* This file is part of libScopes.
* libScopes is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* libScopes is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public License
* along with libScopes.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef th_net_h
#define th_net_h

#ifdef SCOPES_USEBOOSTSERIALIZATION
#include <boost/serialization/list.hpp>
#include <boost/serialization/version.hpp>
#endif // SCOPES_USEBOOSTSERIALIZATION
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <iostream>
#include <math.h>
#include "netstruct.h"

class Net{
	public:
		Net(); //!<default constructor
		Net(NetStruct &str2); //!<new Net with existing NetStruct.
		Net(size_type nr, size_type nc); //!< constructor with allocate.
		Net(const Net& net2); //!<copy constructor.
//		Net(string &st);
//		Net(string &st,size_type &pos);//!< constructor with string
		~Net(); //!<destructor
      Net & operator= (const Net& net2);
//		void initFromString(string &st,size_type &pos);
		void resize(size_type nr, size_type nc); //!<resize all vectors.
		size_type numR(); //!<number of reactions
		size_type numC(); //!<number of compounds
		float at(size_type reaidx,size_type comidx); //!< value at position in stoichiometric matrix
		
		//! Add reaction to the end of reaction list.
		size_type addRea(VS* subs, VS* prds, char rev=0,VF* subsst= NULL,VF* prdsst = NULL,VS* cat=NULL,VS* inhs=NULL,VS* inhd=NULL,VS* prps=NULL);
		//! Replace reaction at a particular index.
		size_type replaceRea(size_type reaidx,VS* subs, VS* prds, char rev=0,VF* subsst= NULL,VF* prdsst = NULL,VS* cat=NULL,VS* inhs=NULL,VS* inhd=NULL,VS* prps=NULL);
		//! Delete reaction at a particular index.
		void delRea(size_type reaidx);
		//! Delete reactions at positons determined by mask
		//~ void delRea(VC* mask);
		//! Delete reactions at positons determined by index list
		//~ void delRea(VS* idxs);
		//! checks whether a particular reaction already exists
		int hasRea(VS* subs, VS* prds, char rev=-10,VF* subsst= NULL,VF* prdsst = NULL);
		void setMembers(size_type comidx,VS* idxs);
      //! set family mebers of a compound
      void setChannels(size_type comidx,VS* idxs);
      //! set family channels of a compound
      void setName(size_type comidx,const std::string& name);
      
		VS* getNeighbors(size_type comidx);//!< reactions in which compound comidx takes part; returns new array
      VS* getMetabolites(size_type reaidx);//!< substrates and products of reactions; return new array
      VS* succs(size_type comidx);//!< successor reactions of compound comidx
		VS* preds(size_type comidx);//!< predecessors reactions of compound comidx
		VS* substrates(size_type reaidx);//!< substrates of reaction reaidx
      VS* products(size_type reaidx);//!< products of reaction reaidx
      VS* inhibitors(size_type reaidx);//!< inhibitors of reaction reaidx
		VS* inhibited(size_type reaidx);//!< inhibited substrates of reaction reaidx
      VS* catalysts(size_type reaidx);//!< catalysts of reaction reaidx
      VS* propagators(size_type reaidx);//!< catalysts of reaction reaidx
      VF* subs_stoich(size_type reaidx);//!< substrate stoichiometries of reaction reaidx
		VF* prod_stoich(size_type reaidx);//!< product stoichiometries of reaction reaidx
      VS* members(size_type comidx);//!< family members of compound
      VS* channels(size_type comidx);//!< family channels of compound
      std::string name(size_type comidx);//!< get name/id of compound
      char rev(size_type reaidx); //!< reversibility of the reaction;
      void setSubstrates(size_type reaidx,VS* subs,VF* subsst=NULL); //!< set substrates of reaction reaidx
      void setProducts(size_type reaidx,VS* prds,VF* prdsst=NULL);//!< set products of reaction reaidx
      void setInhibitors(size_type reaidx,VS* inh);//!< set inhibitors of reaction reaidx
      void setCatalysts(size_type reaidx,VS* cat);//!< set catalysts of reaction reaidx
      void setInhibited(size_type reaidx,VS* inhd);//!< set inhibited substrates of reaction reaidx
      void setPropagators(size_type reaidx,VS* prp);//!< set inhibition propagators of reaction reaidx
      
		char enabled(size_type reaidx); //!< is reaction enabled
      bool hasFamilies(); //!< tells whether protein families are used; automatically set by setMembers
//		string toString();//!< copy network data into a string
//		void appendToString(string &st);//!< copy network data into a string
      std::string printToString();//!< print a summary of network to string
		void print();//!< print a summary of network to stdout
      void print_matrix();
#ifdef SCOPES_USEBOOSTSERIALIZATION
		friend class boost::serialization::access;
		template<class Archive> void serialize(Archive & ar, const unsigned int version) {
		  ar & BOOST_SERIALIZATION_NVP(reaMask);
		  ar & BOOST_SERIALIZATION_NVP(nstr);
		}
#endif // SCOPES_USEBOOSTSERIALIZATION
		VC* reaMask; //!< which reactions are enabled in the current network
//		VC* comMask;
	protected:
      void onChange(); //!< internal: checks whether nstr needs to be copied
		NetStruct* nstr; //!< the network topology
};
// the inline methods

inline bool Net::hasFamilies(){
   return this->nstr->hasFam;
}
inline size_type Net::numR(){
	return this->nstr->numR;
}
inline size_type Net::numC(){
	return this->nstr->numC;
}
/*!
	\param comidx which compound
	
	Note: this returns the original array from the Net object. Do not delete!
*/

inline VS* Net::succs(size_type comidx){
	return (*nstr->CSUC)[comidx];
}
/*!
	\param comidx which compound
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::preds(size_type comidx){
	return (*nstr->CPRE)[comidx];
}
/*!
	\param reaidx which reaction
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::substrates(size_type reaidx){
	return (*nstr->IN)[reaidx];
}
/*!
	\param reaidx which reaction
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::products(size_type reaidx){
	return (*nstr->OUT)[reaidx];
}
/*!
	\param reaidx which reaction
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::inhibitors(size_type reaidx){
	return (*nstr->INH)[reaidx];
}
/*!
	\param reaidx which reaction
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::inhibited(size_type reaidx){
	return (*nstr->CMPI)[reaidx];
}
/*!
\param reaidx which reaction

Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::catalysts(size_type reaidx){
   return (*nstr->CAT)[reaidx];
}
/*!
\param reaidx which reaction

Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::propagators(size_type reaidx){
   return (*nstr->PRP)[reaidx];
}
/*!
	\param reaidx which reaction
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VF* Net::subs_stoich(size_type reaidx){
	return (*nstr->INST)[reaidx];
}
/*!
	\param reaidx which reaction
	
	Note: this returns the original array from the Net object. Do not delete!
*/
inline VF* Net::prod_stoich(size_type reaidx){
	return (*nstr->OUTST)[reaidx];
}
/*!
\param comidx which compound

Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::members(size_type comidx){
   return (*nstr->FAM)[comidx];
}

/*!
\param comidx which compound
*/
inline std::string Net::name(size_type comidx){
   return (*nstr->names)[comidx];
}

/*!
\param comidx which compound

Note: this returns the original array from the Net object. Do not delete!
*/
inline VS* Net::channels(size_type comidx){
   return (*nstr->FCN)[comidx];
}

inline char Net::rev(size_type reaidx){
	return (*nstr->REV)[reaidx];
}
inline char Net::enabled(size_type reaidx){
	return (*reaMask)[reaidx];
}

//ansi-colors for print_matrix
const char COL_RESET[] = "\x1b[0m";
const char COL_RED[]     = "\x1b[31m";
const char COL_GREEN[]   = "\x1b[32m";
const char COL_GREY[]   = "\x1b[37m";
const char COL_BOLD[]   = "\x1b[1m";
#endif
